#!/usr/bin/env python
#
#       pytestgenerator.py
#
#       Copyright 2008 karthikeyan S.<kaarthikeyapreyan@gmail.com>
#
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import os
import sys

import tools
import analyze
import caselogic
import handleargs
import generatepyunit

class TestGenerator:

    def __init__(self,module=None,generatefile=0,writefile=0,\
        writepath=None,option='all'):
        """
        Initialize user requirements
        """
        self.generate=generatefile
        self.write=writefile
        self.writepath=writepath
        self.module=module
        self.option=option

    def importcheck(self,usermod):
        """
        Check for the validity of the module
        Returns the exception incase of import failure
        """
        os.chdir(os.getcwd())
        sys.path.append('.')
        try :
            module=__import__(usermod)
            return (True,module)
        except ImportError, E:
            return (False,str(E))

    def analyzemod(self):
        """
        Analyze the given module on successful module import
        """
        mod_directory=analyze.analyzemodule(self.module)

        if self.generate:
            pyframe = generatepyunit.PyFramework()
            pyframe.writefile("import %s\n\n"%self.module)
            pyframe.writeheader()
            pyframe.writefile("%s module'''\n"%self.module)

            if self.option == 'all':
                self.casegen(mod_directory,self.module,writeobj=pyframe)
            elif self.option == 'function':
                self.casegen(map(lambda id: [id,'function'],\
                    analyze.analyzefunction(self.module)),self.module,pyframe)
            elif self.option == 'method':
                temp_meth=analyze.analyzemethod(self.module)
                map(lambda idx: idx.insert(1,'method'),temp_meth)
                self.casegen(temp_meth,self.module,pyframe)
            elif self.option == 'class':
                self.casegen(map(lambda id: [id,'class'],\
                analyze.analyzeclass(self.module)),self.module,pyframe)

            pyframe.writefooter()
            pyframe.closefile(fname="pytestgen_%s.py"%self.module)

        if self.write :
            tools.writemod(self.module,self.option,mod_directory,self.writepath)
        if not (self.generate or self.write):
            tools.printmod(self.module,self.option,mod_dir=mod_directory)

    def casegen(self,entitylist,module,writeobj):
        """
        Custom module for generating testcases
        """
        self.module=module
        try :
            self.imp_module=__import__(module)
        except Exception,E:
            pass
        for entity in entitylist:
            if entity[1] == 'function'\
                and not entity[0] == None\
                and not (entity[0].startswith('_') or entity[0].startswith('<')):
                self.registercase(entity[0],self.imp_module,0,_writeobj=writeobj)
            elif entity[1] == 'method'\
                and not (entity[0].startswith('_') or entity[0].startswith('<')):
                self.registercase(entity[0],getattr\
                    (self.imp_module,entity[2]),self.module,_writeobj=writeobj)
            elif entity[1] == 'class':
                if '__init__' in getattr(self.imp_module,entity[0]).__dict__:
                    self.registercase('__init__',\
                        getattr(self.imp_module,entity[0]),\
                            entity[0],_writeobj=writeobj)

    def registercase(self,name,modname,classmod,_writeobj=None):

        clargs=None
        try :
            arginfo=handleargs.Args().describeArgs(getattr(modname, name))
        except Exception, E:
            arginfo = None

        if arginfo and not (name.startswith('_') or name.startswith('<')):
            if (len(arginfo[0]) >= 1) and (arginfo[0][0] == 'self') :
                arginfo[0].pop(0)

            clargs=self._classargs(modname,self.imp_module)

            if len(arginfo[0]) == 0:
                caselogic.ArgLogic().noArg(_writeobj,name,mod=modname,\
                    classmod=classmod,clargs=clargs)
            elif len(arginfo[0]) >= 1:
                caselogic.ArgLogic().WhArg(_writeobj,name,\
                    Args=arginfo,mod=modname,classmod=classmod,clargs=clargs)

        elif arginfo and name == "__init__":
            if (len(arginfo[0]) >= 1) and (arginfo[0][0] == 'self'):
                arginfo[0].pop(0)
            if len(arginfo[0]) == 0:
                caselogic.ArgLogic().noArg\
                    (_writeobj,classmod,mod=self.imp_module)
            elif len(arginfo[0]) >= 1:
                caselogic.ArgLogic().WhArg(_writeobj,classmod,Args=arginfo,\
                    mod=self.imp_module)

    def _classargs(self,modattr,module):
        """
        The modattr is the attribute of the module
        with or without the class
        The module is the attribute of the actual module
        """
        clargs=None
        if "__init__" in dir(modattr):
            temp_args=handleargs.Args().describeArgs\
                (getattr(modattr,'__init__'))
            if (len(temp_args) >= 1) and (temp_args[0][0] == 'self'):
                temp_args[0].pop(0)
            clargs=caselogic.ArgLogic()._prediction\
                    (modattr.__name__,Args=temp_args,mod=module)
            if clargs[0]:
                clargs=clargs[0]
            else:
                clargs=None

        return clargs
